package com.ar4j.spring;

import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.springframework.transaction.PlatformTransactionManager;

import com.ar4j.ActiveRecord;
import com.ar4j.ActiveRecordContext;
import com.ar4j.IActiveRecordFactory;
import com.ar4j.NamedSingletonActiveRecordFactory;
import com.ar4j.ActiveRecordJsonWrapper;
import com.ar4j.sql.INamedQuerySource;

/**
 * A wrapper for the NamedActiveRecordFactory singleton. 
 * Supports the same operations as IActiverRecordFactory, but performs an additional
 * step of filling in any new record's context with a data source, named query source (if present),
 * and a platform transaction manager (if present), as well as other settings.
 */
public class ContextSettingActiveRecordFactory implements IActiveRecordFactory {
  private String factoryName;
  private ActiveRecordContext prototypeContext;
  
  public ContextSettingActiveRecordFactory(String factoryName, DataSource dataSource, PlatformTransactionManager platformTransactionManager, INamedQuerySource namedQuerySource, String schemaName) {
    this.factoryName = (factoryName == null ? NamedSingletonActiveRecordFactory.DEFAULT_FACTORY_NAME : factoryName);
    this.prototypeContext = new ActiveRecordContext()
      .setDataSource(dataSource)
      .setNamedQuerySource(namedQuerySource)
      .setPlatformTransactionManager(platformTransactionManager)
      .setSchemaName(schemaName);
    
  }
  
  /**
   * @return an active record factory for the current wrapper's factory name
   */
  public NamedSingletonActiveRecordFactory getFactory() {
    return NamedSingletonActiveRecordFactory.getFactory(factoryName);
  }

  @Override
  public <E extends ActiveRecord<E>> E getActiveRecord(Class<E> domainClass) {
    E out = getFactory().getActiveRecord(domainClass);
    out.getContext().setValuesFrom(prototypeContext);
    return out;
  }
  
  @Override
  public <E extends ActiveRecord<E>> E getActiveRecord(Class<E> domainClass, ActiveRecordJsonWrapper wrapper) {
    E out = getFactory().getActiveRecord(domainClass, wrapper);
    out.getContext().setValuesFrom(prototypeContext);
    return out;
  }
  
  @Override
  public <E extends ActiveRecord<E>> E getActiveRecord(E prototype) {
    E out = getFactory().getActiveRecord(prototype);
    out.getContext().setValuesFrom(prototypeContext);
    return out;
  }
  
  @Override
  public <E extends ActiveRecord<E>> E getActiveRecord(Class<E> domainClass, Map<String, Object> values) {
    E out = getFactory().getActiveRecord(domainClass, values);
    out.getContext().setValuesFrom(prototypeContext);
    return out;
  }

  public String getFactoryName() {
    return factoryName;
  }
  
  public DataSource getDataSource() {
    return prototypeContext.getDataSource();
  }

  public PlatformTransactionManager getPlatformTransactionManager() {
    return prototypeContext.getPlatformTransactionManager();
  }

  public INamedQuerySource getNamedQuerySource() {
    return prototypeContext.getNamedQuerySource();
  }

  @Override
  public String toString() {
    return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
  }
  
}
